﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using ComponentFactory.Krypton.Toolkit;
using System.Runtime.InteropServices;
using LED_Utils.MultitrackControl;

namespace CustomDataBindingControl
{
    [System.ComponentModel.ComplexBindingProperties("DataSource", "DataMember")]
    public partial class TrackViewControl : UserControl
    {
        public TrackViewControl()
        {
            InitializeComponent();
            SetStyle(ControlStyles.Selectable, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            GdiHelper.SetDoubleBuffer(this, true);
            GdiHelper.SetDoubleBuffer(this.kryptonPanel1, true);
            GdiHelper.SetDoubleBuffer(this.flowLayoutPanel, true);




            listChangedHandler = new ListChangedEventHandler(dataManager_ListChanged);
            positionChangedHandler = new EventHandler(dataManager_PositionChanged);
            currentChangedHandler = new EventHandler(dataManager_CurrentChanged);
            itemChangedHandler = new ItemChangedEventHandler(dataManager_ItemChanged);
            propertyChangedHandler = new PropertyChangedEventHandler(TrackViewControl_PropertyChanged);

            BorderThickness = 2;
        }

        protected override void OnBindingContextChanged(EventArgs e)
        {
            this.TryBindDataSource();
            base.OnBindingContextChanged(e);
        }
        public int BorderThickness { get; set; }
        protected override void OnPaint(PaintEventArgs e)
        {

            base.OnPaint(e);
            Pen black = new Pen(Color.Gray, BorderThickness);
            e.Graphics.DrawLine(black,
                new Point(e.ClipRectangle.X, e.ClipRectangle.Y + e.ClipRectangle.Height - BorderThickness),
                new Point(e.ClipRectangle.X + e.ClipRectangle.Width, e.ClipRectangle.Y + e.ClipRectangle.Height - BorderThickness));
        }

        private ListChangedEventHandler listChangedHandler;
        private EventHandler positionChangedHandler;
        private EventHandler currentChangedHandler;
        private ItemChangedEventHandler itemChangedHandler;
        private PropertyChangedEventHandler propertyChangedHandler;



        private CurrencyManager dataManager;
        private string dataMember;



        public string DataMember
        {
            get
            {
                return dataMember;
            }
            set
            {
                dataMember = value;
                TryBindDataSource();
            }
        }

        private object _dataSource;


        [AttributeProvider(typeof(IListSource))]
        [RefreshProperties(RefreshProperties.Repaint)]
        [DefaultValue(null)]
        [Category("Data")]
        public object DataSource
        {
            get { return _dataSource; }
            set
            {
                _dataSource = value;
                //_innerBindingSource = new BindingSource(_dataSource, ""); 

                //if (_dataSource != null)
                //{
                //    //if (_dataSource is IBindingList)
                //    //{
                //    //    ((IBindingList)_dataSource).ListChanged += new ListChangedEventHandler(CustomTrackEditorControl_ListChanged);
                //    //}
                //    ((CurrencyManager)this.BindingContext[_dataSource]).ListChanged += new ListChangedEventHandler(CustomTrackEditorControl_ListChanged);
                //    this.BindingContext[_dataSource].PositionChanged += new EventHandler(CustomTrackControl1_PositionChanged); 
                //}
                TryBindDataSource();

            }
        }

        private IList InnerList
        {
            get
            {
                if (dataManager == null)
                    return null;
                return dataManager.List;
            }
        }

        void dataManager_PositionChanged(object sender, EventArgs e)
        {
            //OnSelectedFrameChanged();
        }

        public object SelectedFrame
        {
            get
            {
                if (BindingContext[_dataSource].Position < 0)
                    return null;
                return BindingContext[_dataSource].Current;

            }
        }

        public event EventHandler SelectedFrameChanged;
        private void OnSelectedFrameChanged()
        {
            if (SelectedFrameChanged != null)
            {
                SelectedFrameChanged(this, EventArgs.Empty);
            }
        }


        void dataManager_ListChanged(object sender, ListChangedEventArgs e)
        {
            switch (e.ListChangedType)
            {
                case ListChangedType.ItemAdded:
                    AddFrameControlInternal(e.NewIndex);
                    SetCurrent(e.NewIndex);

                    break;
                case ListChangedType.ItemDeleted:
                    RemoveFrameControlInternal(e.NewIndex);
                    SetCurrent(e.NewIndex - 1);
                    OnSelectedFrameChanged();
                    break;
                case ListChangedType.ItemMoved:
                case ListChangedType.Reset:
                    RefreshView();
                    break;
                case ListChangedType.PropertyDescriptorAdded:
                    break;
                case ListChangedType.PropertyDescriptorDeleted:
                    break;
                case ListChangedType.ItemChanged:
                    //case ListChangedType.PropertyDescriptorChanged:

                    object item = InnerList[e.NewIndex];
                    FrameViewControl ctrl = flowLayoutPanel.Controls[e.NewIndex] as FrameViewControl;
                    MapData(item, ctrl);
                    break;
                default:
                    break;
            }
        }

        public List<FrameViewControl> Frames
        {

            get { return flowLayoutPanel.Controls.OfType<FrameViewControl>().ToList(); }
        }

        private Control FindControlByDataSource(object dataSource)
        {
            foreach (Control item in flowLayoutPanel.Controls)
            {
                if (!(item is FrameViewControl))
                    continue;

                object controlDataSource = ((FrameViewControl)item).DataSource;
                if (controlDataSource != null && controlDataSource.Equals(dataSource))
                    return item;

            }
            return null;
        }
        void TrackViewControl_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            object item = sender;
            FrameViewControl ctrl = FindControlByDataSource(item) as FrameViewControl;
            if (ctrl == null)
                return;

            MapData(item, ctrl);
            OnSelectedFrameChanged();
        }

        private void MapData(object item, FrameViewControl ctrl)
        {
            if (item is DataRowView)
            {
                PropertyDescriptorCollection pdc = this.dataManager.GetItemProperties();
                //PropertyDescriptor startColor = pdc["StartColor"];
                object startColorObject = ((DataRowView)item).Row["StartColor"];  //startColor.GetValue(((DataRowView)item).Row);
                ctrl.StartColor = startColorObject == null || startColorObject is DBNull ? Color.Empty : (Color)startColorObject;

                //PropertyDescriptor endColor = pdc["EndColor"];
                object endColorObject = ((DataRowView)item).Row["EndColor"]; //endColor.GetValue(((DataRowView)item).Row);
                ctrl.EndColor = endColorObject == null || endColorObject is DBNull ? Color.Empty : (Color)endColorObject;

                PropertyDescriptor width = pdc["FrameDuration"];
                object widthObject = ((DataRowView)item).Row["FrameDuration"]; //endColor.GetValue(((DataRowView)item).Row);
                ctrl.FrameWidth = widthObject == null || widthObject is DBNull ? 0f : Convert.ToSingle(widthObject);

            }
            else
            {
                PropertyDescriptorCollection pdc = this.dataManager.GetItemProperties();
                PropertyDescriptor startColor = pdc["StartColor"];
                ctrl.StartColor = (Color)startColor.GetValue(item);

                PropertyDescriptor endColor = pdc["EndColor"];
                ctrl.EndColor = (Color)endColor.GetValue(item);

                PropertyDescriptor width = pdc["FrameDuration"];
                ctrl.FrameWidth = (float)width.GetValue(item);

            }
            //ctrl.StartColor = (Color)item.GetType().GetProperty("StartColor").GetValue(item, null);
            //ctrl.EndColor = (Color)item.GetType().GetProperty("EndColor").GetValue(item, null);

        }

        private void TryBindDataSource()
        {
            //if (_dataSource == null)
            //    return;

            //if (!(_dataSource is IEnumerable))
            //    return;

            //RefreshView();
            if (this.DataSource == null ||
                base.BindingContext == null)
                return;

            CurrencyManager cm;
            try
            {
                cm = (CurrencyManager)base.BindingContext[this.DataSource, this.DataMember];
            }
            catch (System.ArgumentException)
            {
                // If no CurrencyManager was found
                return;
            }
            if (this.dataManager != cm)
            {
                // Unwire the old CurrencyManager
                if (this.dataManager != null)
                {
                    this.dataManager.ListChanged -= listChangedHandler;
                    this.dataManager.PositionChanged -= positionChangedHandler;
                    this.dataManager.CurrentChanged -= currentChangedHandler;
                    this.dataManager.ItemChanged -= itemChangedHandler;

                }
                this.dataManager = cm;
                // Wire the new CurrencyManager
                if (this.dataManager != null)
                {
                    this.dataManager.ListChanged += listChangedHandler;
                    this.dataManager.PositionChanged += positionChangedHandler;
                    this.dataManager.CurrentChanged += currentChangedHandler;
                    this.dataManager.ItemChanged += itemChangedHandler;
                    this.dataManager.CurrentItemChanged += new EventHandler(dataManager_CurrentItemChanged);

                }

                // Update metadata and data
                //calculateColumns();
                //updateAllData();
                RefreshView();
            }
        }

        void dataManager_CurrentItemChanged(object sender, EventArgs e)
        {
            //MessageBox.Show("dataManager_CurrentItemChanged");
        }

        void dataManager_ItemChanged(object sender, ItemChangedEventArgs e)
        {
            //MessageBox.Show("dataManager_ItemChanged"); 
        }

        private void dataManager_CurrentChanged(object sender, EventArgs e)
        {
            //MessageBox.Show("dataManager_CurrentChanged");  
        }


        private void AddFrameControlInternal(int index)
        {
            SuspendLayout();

            object item = (InnerList)[index];

            if (item is INotifyPropertyChanged)
            {
                ((INotifyPropertyChanged)item).PropertyChanged += propertyChangedHandler;
            }

            FrameViewControl ctrl = CreateControl(item);


            flowLayoutPanel.Controls.Add(ctrl);

            ResumeLayout();
        }

        private PropertyChangedEventHandler _propertyChangedHandler;

        private FrameViewControl CreateControl(object item)
        {
            FrameViewControl ctrl = new FrameViewControl();
            ctrl.Enter += new EventHandler(ctrl_Enter);
            ctrl.Click += new EventHandler(ctrl_Enter);
            ctrl.KeyDown += new KeyEventHandler(ctrl_KeyDown);
            ctrl.KeyPress += new KeyPressEventHandler(ctrl_KeyPress);


            ctrl.Margin = new Padding(0);
            ctrl.Padding = new Padding(0);
            ctrl.Height = this.Height - this.Margin.All * 2 - this.Padding.All * 2 - 2;
            ctrl.FrameDeleting += new EventHandler(ctrl_FrameDeleting);
            MapData(item, ctrl);
            //ctrl.StartColor = (Color)item.GetType().GetProperty("StartColor").GetValue(item,null);
            //ctrl.EndColor = (Color)item.GetType().GetProperty("EndColor").GetValue(item, null);

            ctrl.DataSource = item;
            //Binding binding1 = new Binding("StartColor", item, "StartColor", true, DataSourceUpdateMode.OnPropertyChanged);
            //Binding binding2 = new Binding("EndColor", item, "EndColor", true, DataSourceUpdateMode.OnPropertyChanged);
            //Binding binding3 = new Binding("FrameWidth", item, "FrameDuration", true, DataSourceUpdateMode.OnPropertyChanged);

            //ctrl.DataBindings.Add(binding1);
            //ctrl.DataBindings.Add(binding2);
            //ctrl.DataBindings.Add(binding3);
            return ctrl;
        }




        void ctrl_FrameDeleting(object sender, EventArgs e)
        {
            this.dataManager.List.Remove(((FrameViewControl)sender).DataSource);
        }



        private void RemoveFrameControlInternal(int index)
        {
            SuspendLayout();


            flowLayoutPanel.Controls.RemoveAt(index);
            ResumeLayout();
        }


        BindingSource _innerBindingSource;
        private void RefreshView()
        {
            if (InnerList.Count < 1)
                return;

            SuspendLayout();
            flowLayoutPanel.Controls.Clear();
            foreach (var item in InnerList)
            {
                FrameViewControl ctrl = CreateControl(item);

                flowLayoutPanel.Controls.Add(ctrl);
            }
            ResumeLayout();
        }

        void ctrl_Enter(object sender, EventArgs e)
        {
            FrameViewControl ctrl = sender as FrameViewControl;
            if (ctrl == null)
                return;

            int index = this.flowLayoutPanel.Controls.IndexOf(ctrl);
            //this.BindingContext[_dataSource].Position = index;

            //RefreshSelection(index);
            SetCurrent(index);

            //OnSelectedFrameChanged();

        }

        private void SetCurrent(int index)
        {
            //int index = flowLayoutPanel.Controls.IndexOf(ctrl);
            if (index < 0)
            {
                this.dataManager.SuspendBinding();
            }
            else
            {
                this.dataManager.ResumeBinding();
                this.dataManager.Position = index;
            }
            OnSelectedFrameChanged();
            RefreshSelection(index);
        }

        private void RefreshSelection(int indexToSelect)
        {
            FrameViewControl ctrl = null;

            if (indexToSelect >= 0)
            {
                ctrl = this.flowLayoutPanel.Controls[indexToSelect] as FrameViewControl;
            }

            foreach (FrameViewControl item in this.flowLayoutPanel.Controls)
            {
                if (ctrl != null && item.Equals(ctrl))
                {
                    ctrl.Selected = true;
                }
                else
                {
                    item.Selected = false;
                }
            }
          
        }



        private void TrackViewControl_Load(object sender, EventArgs e)
        {

        }



        public PaletteBack StateCommon { get { return kryptonPanel1.StateCommon; } }
        public PaletteBack StateNormal { get { return kryptonPanel1.StateNormal; } }

        private void flowLayoutPanel_Leave(object sender, EventArgs e)
        {
            // StateCommon.ColorStyle = ComponentFactory.Krypton.Toolkit.PaletteColorStyle.Inherit;
            //  StateCommon.Color1 = Color.Transparent ;

        }

        public void Select(bool selected)
        {
            if (selected)
            {
                StateCommon.ColorStyle = ComponentFactory.Krypton.Toolkit.PaletteColorStyle.Solid;
                StateCommon.Color1 = Color.Gray;
            }
            else
            {
                StateCommon.ColorStyle = ComponentFactory.Krypton.Toolkit.PaletteColorStyle.Inherit;
                StateCommon.Color1 = Color.Transparent;
            }
            RefreshSelection(-1);
        }

        private void flowLayoutPanel_Enter(object sender, EventArgs e)
        {
            // OnEnter(e);
            //// StateCommon.ColorStyle = ComponentFactory.Krypton.Toolkit.PaletteColorStyle.Solid;
            // StateCommon.Color1 = Color.Gray;

        }

        protected override void OnClick(EventArgs e)
        {
            base.OnClick(e);
            //StateCommon.ColorStyle = ComponentFactory.Krypton.Toolkit.PaletteColorStyle.Solid;
            //StateCommon.Color1 = Color.Gray;

        }

        private void kryptonPanel1_Enter(object sender, EventArgs e)
        {
            // OnEnter(e);

        }

        private void TrackViewControl_Enter(object sender, EventArgs e)
        {
            // StateCommon.ColorStyle = ComponentFactory.Krypton.Toolkit.PaletteColorStyle.Solid;
            // StateCommon.Color1 = Color.Gray;

            //OnEnter(e);
            SetCurrent(-1);
        }

        public void PerformScale(int percents)
        {
            //foreach (FrameViewControl  item in flowLayoutPanel.Controls  )
            //{
            //    item.ScaleFactor = percents;
            //}
            flowLayoutPanel.PerformScale(percents);
        }

        private int _initialScale;
        public int InitialScale
        {
            get
            {
                return flowLayoutPanel.InitialScale;
            }
            set
            {
                flowLayoutPanel.InitialScale = value;
            }
        }

        private void TrackViewControl_KeyDown(object sender, KeyEventArgs e)
        {
        }

        private void flowLayoutPanel_Click(object sender, EventArgs e)
        {
            OnEnter(e);
            SetCurrent(-1);
            //OnSelectedFrameChanged();
            //RefreshSelection(-1);
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
            OnEnter(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            //MessageBox.Show(e.KeyCode.ToString());
            if (e.KeyCode == Keys.Left)
            {
                if (this.dataManager.Position <= 0)
                    return;
                SetCurrent(this.dataManager.Position-1);
            }
            else if (e.KeyCode == Keys.Right  )
            {
                if (this.dataManager.Position>=this.dataManager.Count-1)
                    return;
                SetCurrent(this.dataManager.Position+1);
            }
        }

        void ctrl_KeyDown(object sender, KeyEventArgs e)
        {
            OnKeyDown(e);
        }

        void ctrl_KeyPress(object sender, KeyPressEventArgs e)
        {
            // MessageBox.Show(e.KeyChar.ToString());

        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == Keys.Left || keyData == Keys.Right||keyData == Keys.Up || keyData == Keys.Down )
            {
                OnKeyDown(new KeyEventArgs(keyData));
            }
            return base.ProcessCmdKey(ref msg, keyData);

        }
    }



    public class SelectableFlowLayoutPanel: FlowLayoutPanel 
    {
        public SelectableFlowLayoutPanel():base()
        {
            SetStyle(ControlStyles.Selectable, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }

        double scale = 100;
        double previousScale = 100;
        double delta = 1;

        float calcFactor = 1;



        public void PerformScroll(int offset)
        {
            Point p = AutoScrollPosition;
            AutoScrollPosition = new Point(Math.Abs(p.X) + offset, p.Y);
            //ShowInfo();


        }
        public void PerformScrollPage(int pageCount)
        {
            PerformScroll(pageCount * ClientRectangle.Width);
            //ShowInfo();

        }

        [DllImport("user32.dll")]
        static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);

        private const int SB_HORZ = 0;

        protected override void OnSizeChanged(EventArgs e)
        {
            ShowScrollBar(Handle, SB_HORZ, false);
            base.OnSizeChanged(e);
        }

        #region ICustomScale Members

        public virtual void PerformScale(int percents)
        {
            previousScale = scale;
            scale = percents;

            delta = scale - previousScale;


            //int x = scale - previousScale > 0 ? 1 : -1;
            int x = 1;
            //calcFactor=(float)(scale / previousScale);
            calcFactor = 1f + (float)(x * delta / previousScale);
            SuspendLayout();
            foreach (Control item in Controls)
            {
                if (item is ICustomScale)
                {
                    ((ICustomScale)item).InitialScale = InitialScale;
                    ((ICustomScale)item).ScaleFactor = ScaleFactor;

                }
                if (item is FrameViewControl)
                {
                    ((FrameViewControl)item).Scaling = true;
                }
                item.Scale(new SizeF(calcFactor, 1f));
                if (item is FrameViewControl)
                {
                    ((FrameViewControl)item).Scaling = false;
                }
            }
            ResumeLayout();
            //ShowInfo();
        }


        private int _initialScale;
        public int InitialScale
        {
            get
            {
                return _initialScale;
            }
            set
            {
                _initialScale = value;
            }
        }

        #endregion

        #region ICustomScale Members


        public float ScaleFactor
        {
            get
            {
                return calcFactor;
            }
            set
            {
                //calcFactor = ;
            }
        }

        #endregion
    }

    public class TestFrame
    {
        public Color StartColor { get; set; }
    }

}
